<!DOCTYPE html>
<html  lang="zh-CN" >
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, maximum-scale=5, viewport-fit=cover">
    <title>ESP-IDF学习笔记-RMT的使用 | LO_StacNet的火柴盒</title>
    <meta name="description" content="ESP-IDF学习笔记-RMT的使用作为物联网芯片，ESP32C3包含一个RMT外设，可以用来产生一些单线协议信号。可以实现NEC协议(红外遥控器使用)，或者驱动WS2812灯珠。这边以WS2812的协议为例，学习使用该外设。">
<meta property="og:type" content="article">
<meta property="og:title" content="ESP-IDF学习笔记-RMT的使用">
<meta property="og:url" content="https://lostacnet.top/post/32304/">
<meta property="og:site_name" content="LO_StacNet的火柴盒">
<meta property="og:description" content="ESP-IDF学习笔记-RMT的使用作为物联网芯片，ESP32C3包含一个RMT外设，可以用来产生一些单线协议信号。可以实现NEC协议(红外遥控器使用)，或者驱动WS2812灯珠。这边以WS2812的协议为例，学习使用该外设。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://s21.ax1x.com/2024/08/08/pkznnW8.png">
<meta property="og:image" content="https://s21.ax1x.com/2024/08/08/pkznKSS.png">
<meta property="og:image" content="https://s21.ax1x.com/2024/08/08/pkznMQg.png">
<meta property="article:published_time" content="2024-03-22T17:04:30.000Z">
<meta property="article:modified_time" content="2024-08-08T04:25:16.897Z">
<meta property="article:author" content="LO_StacNet">
<meta property="article:tag" content="ESP-IDF">
<meta property="article:tag" content="ESP32">
<meta property="article:tag" content="RMT">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://s21.ax1x.com/2024/08/08/pkznnW8.png">

    
    <link rel="icon" href="/images/favicon.ico" type="image/x-icon">

    
<link rel="stylesheet" href="/css/common.min.css">



    
        <link href="//cdn.jsdelivr.net/npm/katex@0.9.0/dist/katex.min.css" rel="stylesheet">
    
    
    
    
        <link href="//cdn.jsdelivr.net/npm/lightgallery.js@1.1.3/dist/css/lightgallery.min.css" rel="stylesheet">
    
    
    
<link rel="stylesheet" href="/css/iconfont.min.css">

    
<meta name="generator" content="Hexo 6.3.0"><style>mjx-container[jax="SVG"] {
  direction: ltr;
}

mjx-container[jax="SVG"] > svg {
  overflow: visible;
}

mjx-container[jax="SVG"][display="true"] {
  display: block;
  text-align: center;
  margin: 1em 0;
}

mjx-container[jax="SVG"][justify="left"] {
  text-align: left;
}

mjx-container[jax="SVG"][justify="right"] {
  text-align: right;
}

g[data-mml-node="merror"] > g {
  fill: red;
  stroke: red;
}

g[data-mml-node="merror"] > rect[data-background] {
  fill: yellow;
  stroke: none;
}

g[data-mml-node="mtable"] > line[data-line] {
  stroke-width: 70px;
  fill: none;
}

g[data-mml-node="mtable"] > rect[data-frame] {
  stroke-width: 70px;
  fill: none;
}

g[data-mml-node="mtable"] > .mjx-dashed {
  stroke-dasharray: 140;
}

g[data-mml-node="mtable"] > .mjx-dotted {
  stroke-linecap: round;
  stroke-dasharray: 0,140;
}

g[data-mml-node="mtable"] > svg {
  overflow: visible;
}

[jax="SVG"] mjx-tool {
  display: inline-block;
  position: relative;
  width: 0;
  height: 0;
}

[jax="SVG"] mjx-tool > mjx-tip {
  position: absolute;
  top: 0;
  left: 0;
}

mjx-tool > mjx-tip {
  display: inline-block;
  padding: .2em;
  border: 1px solid #888;
  font-size: 70%;
  background-color: #F8F8F8;
  color: black;
  box-shadow: 2px 2px 5px #AAAAAA;
}

g[data-mml-node="maction"][data-toggle] {
  cursor: pointer;
}

mjx-status {
  display: block;
  position: fixed;
  left: 1em;
  bottom: 1em;
  min-width: 25%;
  padding: .2em .4em;
  border: 1px solid #888;
  font-size: 90%;
  background-color: #F8F8F8;
  color: black;
}

foreignObject[data-mjx-xml] {
  font-family: initial;
  line-height: normal;
  overflow: visible;
}

.MathJax path {
  stroke-width: 3;
}

mjx-container[display="true"] {
  overflow: auto hidden;
}

mjx-container[display="true"] + br {
  display: none;
}
</style></head>

    <body>
        <header class="header header-fixture">
    <div class="profile-search-wrap flex sm:block">
        
        
        <div class="profile sm:text-center md:px-1 lg:px-3 sm:pb-4 sm:pt-6">
            <a id="avatar" role="link" href="http://www.lostacnet.top" class="inline-block lg:w-16 lg:h-16 w-8 h-8 m-2" target="_blank" rel="noopener" rel="noreferrer" >
                <img src="/images/avatar.jpg" class="rounded-full" alt="avatar">
            </a>
            <h2 id="name" class="hidden lg:block">LO_StacNet</h2>
            <h3 id="title" class="hidden lg:block">电子玩家 &amp; 理想主义</h3>
            
            <small id="location" class="hidden lg:block">
                <i class="iconfont icon-map-icon"></i>
                Sichuan, China
            </small>
            
        </div>
        
        
<div class="search flex-1 flex lg:inline-block sm:hidden lg:px-4 lg:mt-2 lg:mb-4 lg:w-full">
    <form id="search-form" class="my-auto flex-1 lg:border lg:border-solid lg:border-gray-200">
        <div class="input-group table bg-gray-100 lg:bg-white w-full">
            <input id="search-input" type="text" placeholder="搜索" class="inline-block w-full bg-gray-100 lg:bg-white p-1">
            <span class="table-cell">
                <button name="search tigger button" disabled>
                    <i class="iconfont icon-search m-2"></i>
                </button>
            </span>
        </div>
    </form>
        
<div id="content-json" data-placeholder="搜索" class="invisible hidden">/content.json</div>
<script id="search-teamplate" type="text/html" data-path="/content.json">
    <div>
        <div class="search-header bg-gray-400">
            <input id="actual-search-input" model="keyword" ref="input" class="inline-block w-full h-10 px-2 py-1" placeholder="搜索" type="text">
        </div>
        <div class="search-result bg-gray-200">
            {{#each searchPosts}}
            <a href="/{{ path }}" class="result-item block px-2 pb-3 mb-1 pt-1 hover:bg-indigo-100">
                <i class="iconfont icon-file"></i>
                <h1 class="result-title inline font-medium text-lg">{{ title }}</h1>
                <p class="result-content text-gray-600 text-sm">{{{ text }}}</p>
            </a>
            {{/each}}
        </div>
    </div>
</script>

</div>


        <button name="menu toogle button" id="menu-toggle-btn" class="block sm:hidden p-3" role="button" aria-expanded="false">
            <i class="iconfont icon-hamburger"></i>
        </button>
    </div>
    <nav id="menu-nav" class="hidden sm:flex flex-col">
        
        
            <div class="menu-item menu-home" role="menuitem">
                <a href="/.">
                    <i class="iconfont icon-home" aria-hidden="true"></i>
                    <span class="menu-title">首页</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-archives" role="menuitem">
                <a href="/archives">
                    <i class="iconfont icon-archive" aria-hidden="true"></i>
                    <span class="menu-title">归档</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-categories" role="menuitem">
                <a href="/categories">
                    <i class="iconfont icon-folder" aria-hidden="true"></i>
                    <span class="menu-title">分类</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-tags" role="menuitem">
                <a href="/tags">
                    <i class="iconfont icon-tag" aria-hidden="true"></i>
                    <span class="menu-title">标签</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-links" role="menuitem">
                <a href="/links">
                    <i class="iconfont icon-friend" aria-hidden="true"></i>
                    <span class="menu-title">友链</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-about" role="menuitem">
                <a href="/about">
                    <i class="iconfont icon-cup" aria-hidden="true"></i>
                    <span class="menu-title">关于</span>
                </a>
            </div>
        
        
<div class="social-links flex sm:flex-col lg:hidden mt-5">
    
        <span class="social-item text-center">
            <a target="_blank" rel="noopener" href="https://github.com/LOStacNet">
                <i class="iconfont social-icon icon-github"></i>
                <span class="menu-title hidden lg:inline">menu.github</span>
            </a>
        </span>
    
        <span class="social-item text-center">
            <a target="_blank" rel="noopener" href="https://gitee.com/LOStacNet">
                <i class="iconfont social-icon icon-project"></i>
                <span class="menu-title hidden lg:inline">menu.project</span>
            </a>
        </span>
    
</div>


    </nav>
</header>

        <section class="main-section">
            
    <main class="flex-1 px-4 py-14 md:px-5 lg:px-8 lg:py-4 relative min-h-screen">
    

    <article class="content article article-archives article-type-list" itemscope="">
        <header class="article-header">
            
    
        <h1 class="article-title text-lg" itemprop="name">
            ESP-IDF学习笔记-RMT的使用
        </h1>
    



            <p class="article-meta mb-3 text-xs">
                <span class="article-date">
    <i class="iconfont icon-calendar-check"></i>
	<a href="/post/32304/" class="article-date">
	  <time datetime="2024-03-22T17:04:30.000Z" itemprop="datePublished">3月 23</time>
	</a>
</span>

                
    <span class="article-category">
    <i class="iconfont icon-folder"></i>
    <a class="article-category-link" href="/categories/ESP32%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">ESP32学习笔记</a>
  </span>


                
    <span class="article-tags">
    <i class="iconfont icon-tag"></i>
    <a class="article-tag-none-link" href="/tags/ESP-IDF/" rel="tag">ESP-IDF</a>, <a class="article-tag-none-link" href="/tags/ESP32/" rel="tag">ESP32</a>, <a class="article-tag-none-link" href="/tags/RMT/" rel="tag">RMT</a>
  </span>


                <span class="_partial/post-comment"><i class="icon icon-comment"></i>
                    <a href="/post/32304/#comments" class="article-comment-link">
                        评论
                    </a>
                </span>
                
    
        <span class="post-wordcount" itemprop="wordCount">字数统计: 2.1k(字)</span>
    
    
        <span class="post-readcount" itemprop="timeRequired">阅读时长: 9(分)</span>
    


            </p>
        </header>
        <div class="marked-body article-body">
            <h1 id="ESP-IDF学习笔记-RMT的使用"><a href="#ESP-IDF学习笔记-RMT的使用" class="headerlink" title="ESP-IDF学习笔记-RMT的使用"></a>ESP-IDF学习笔记-RMT的使用</h1><p>作为物联网芯片，ESP32C3包含一个RMT外设，可以用来产生一些单线协议信号。可以实现NEC协议(红外遥控器使用)，或者驱动WS2812灯珠。这边以WS2812的协议为例，学习使用该外设。</p>
<span id="more"></span>

<p><a target="_blank" rel="noopener" href="https://docs.espressif.com/projects/esp-idf/zh_CN/v5.1/esp32c3/api-reference/peripherals/rmt.html#introduction">官方文档</a></p>
<p>相关声明在<code>driver/rmt_tx.h</code>或者<code>driver/rmt_rx.h</code>下。</p>
<h2 id="外设简介"><a href="#外设简介" class="headerlink" title="外设简介"></a>外设简介</h2><p>有一些通信协议使用了单线协议，利用高低电平的不同时间表示0和1，这样可以节省信道数量，但是这对于软件来说很不好实现。比如常用的红外协议NEC：</p>
<p><img src="https://s21.ax1x.com/2024/08/08/pkznnW8.png" alt="image-20240323111218986"></p>
<p>需要控制高电平时间和低电平时间来分别传输0和1，这对软件来说比较难控制，因此ESP32包含了一个专用外设RMT用来实现这类时序。</p>
<p>ESP32C3有一个RMT外设，包含多个通道，每个通道可单独设置为发送和接收。RMT使用<code>RMT symbol</code>配置高低电平的时间，在IDF中数据类型为<code>rmt_symbol_word_t</code>。</p>
<p><img src="https://s21.ax1x.com/2024/08/08/pkznKSS.png" alt="image-20240323112953162"></p>
<p>用15bit设定持续多长的RMT ticks，一个bit(L)设定是高电平还是低电平。翻译过来就是一个这样的信息：{(11,high,7,low),(5,high,5l,ow)}。</p>
<h2 id="发送通道"><a href="#发送通道" class="headerlink" title="发送通道"></a>发送通道</h2><h3 id="安装TX通道"><a href="#安装TX通道" class="headerlink" title="安装TX通道"></a>安装TX通道</h3><p>首先我们需要安装通道。一个通道由<code>rmt_channel_handle_t</code>句柄进行管理，使用<code>rmt_tx_channel_config_t</code>进行设置，使用<code>rmt_new_tx_channel()</code>进行创建。</p>
<p>rmt_tx_channel_config_t定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">    <span class="type">gpio_num_t</span> gpio_num;        </span><br><span class="line">    <span class="type">rmt_clock_source_t</span> clk_src;</span><br><span class="line">    <span class="type">uint32_t</span> resolution_hz;     </span><br><span class="line">    <span class="type">size_t</span> mem_block_symbols;  </span><br><span class="line">    <span class="type">size_t</span> trans_queue_depth;   </span><br><span class="line">    <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">        <span class="type">uint32_t</span> invert_out: <span class="number">1</span>;   </span><br><span class="line">        <span class="type">uint32_t</span> with_dma: <span class="number">1</span>;     </span><br><span class="line">        <span class="type">uint32_t</span> io_loop_back: <span class="number">1</span>; </span><br><span class="line">        <span class="type">uint32_t</span> io_od_mode: <span class="number">1</span>;   </span><br><span class="line">    } flags;                      </span><br><span class="line">} <span class="type">rmt_tx_channel_config_t</span>;</span><br></pre></td></tr></table></figure>

<ul>
<li>gpio_num:设置输出IO引脚。</li>
<li>clk_src:选择时钟源，一般选择<code>RMT_CLK_SRC_DEFAULT</code>即APB时钟。</li>
<li>resolution_hz:设置RMT tick的频率。</li>
<li>mem_block_symbols:必须为偶数。普通模式下设置该通道使用的RMT内存块数量，至少为 48(ESP32C3没有RMTDMA，因此不考虑DMA模式)-越大灯珠闪烁越小</li>
<li>trans_queue_depth:内部事务队列深度。队列越深，在待处理队列中可以准备的事务越多。</li>
<li>invert_out:设置输出是否反相(电平相反)</li>
<li>with_dma:是否开启dma，C3没有，因此不用管。</li>
<li>io_loop_back:启用通道所分配的 GPIO 上的输入和输出功能，将发送通道和接收通道绑定到同一个 GPIO 上，从而实现回环功能。配合io_od_mode可以实现一些单线协议。</li>
<li>io_od_mode:配合io_loop_back，将io口设置为开漏模式，这样可以监控输入。</li>
</ul>
<p>使用例：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">rmt_channel_handle_t</span> led_chan = <span class="literal">NULL</span>;</span><br><span class="line"><span class="type">rmt_tx_channel_config_t</span> tx_chan_config = {</span><br><span class="line">    .clk_src = RMT_CLK_SRC_DEFAULT, <span class="comment">// select source clock</span></span><br><span class="line">    .gpio_num = <span class="number">0</span>,</span><br><span class="line">    .mem_block_symbols = <span class="number">64</span>, <span class="comment">// increase the block size can make the LED less flickering</span></span><br><span class="line">    .resolution_hz = <span class="number">10000000</span>,</span><br><span class="line">    .trans_queue_depth = <span class="number">4</span>, <span class="comment">// set the number of transactions that can be pending in the background</span></span><br><span class="line">    .flags.invert_out = <span class="literal">false</span>,   </span><br><span class="line">	.flags.with_dma = <span class="literal">false</span>, </span><br><span class="line">};</span><br><span class="line">ESP_ERROR_CHECK(rmt_new_tx_channel(&amp;tx_chan_config, &amp;led_chan));</span><br></pre></td></tr></table></figure>

<p>如果需要卸载，使用<code>rmt_del_channel() </code>函数释放资源。</p>
<h3 id="载波调制"><a href="#载波调制" class="headerlink" title="载波调制"></a>载波调制</h3><p>RMT发生器可以将信号调制到高频：</p>
<p><img src="https://s21.ax1x.com/2024/08/08/pkznMQg.png" alt="image-20240324215824803"></p>
<p>相关配置结构体为<code>rmt_carrier_config_t</code></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">    <span class="type">uint32_t</span> frequency_hz; <span class="comment">/*载波频率 */</span></span><br><span class="line">    <span class="type">float</span> duty_cycle;      <span class="comment">/*载波占空比 0~1 */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">        <span class="type">uint32_t</span> polarity_active_low: <span class="number">1</span>; <span class="comment">/*极性选择，决定载波调制到高电平还是低电平，默认是高电平 */</span></span><br><span class="line">        <span class="type">uint32_t</span> always_on: <span class="number">1</span>;           <span class="comment">/*设置空闲时是否发送载波 */</span></span><br><span class="line">    } flags;                             </span><br><span class="line">} <span class="type">rmt_carrier_config_t</span>;</span><br></pre></td></tr></table></figure>

<p>使用<code>rmt_apply_carrier()</code>应用到具体通道。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">rmt_carrier_config_t</span> tx_carrier_cfg = {</span><br><span class="line">    .duty_cycle = <span class="number">0.33</span>,                 <span class="comment">// 载波占空比为 33%</span></span><br><span class="line">    .frequency_hz = <span class="number">38000</span>,              <span class="comment">// 38 KHz</span></span><br><span class="line">    .flags.polarity_active_low = <span class="literal">false</span>, <span class="comment">// 载波应调制到高电平</span></span><br><span class="line">};</span><br><span class="line"><span class="comment">// 将载波调制到 TX 通道</span></span><br><span class="line">ESP_ERROR_CHECK(rmt_apply_carrier(tx_chan, &amp;tx_carrier_cfg));</span><br></pre></td></tr></table></figure>

<h3 id="RMT编码器"><a href="#RMT编码器" class="headerlink" title="RMT编码器"></a>RMT编码器</h3><p>对于RMT外设来说，它只会将内存块中的RMT Symbol按顺序发出，并没有解析byte数据的能力，因此IDF在驱动层面添加了一个编码器事务机制，用于在传输中将数据编码为RMT Symbol。由于RMT 内存块无法一次性容纳所有数据，在单个事务中，会多次调用编码函数。同时编码器函数<strong>运行在中断</strong>中，因此建议将其放入IRAM空间运行。</p>
<p>编码器的具体编写方式可以参考<a target="_blank" rel="noopener" href="https://docs.espressif.com/projects/esp-idf/zh_CN/v5.0.6/esp32c3/api-reference/peripherals/rmt.html#nec-rmt">官方文档</a>，给出了NEC协议的编码器。</p>
<p>这里给出官方例程中的LED编码器实现:</p>
<ul>
<li>led_strip_encoder.h</li>
</ul>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * SPDX-License-Identifier: Apache-2.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdint.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"driver/rmt_encoder.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span> {</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief Type of led strip encoder configuration</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">    <span class="type">uint32_t</span> resolution; <span class="comment">/*!&lt; Encoder resolution, in Hz */</span></span><br><span class="line">} <span class="type">led_strip_encoder_config_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief Create RMT encoder for encoding LED strip pixels into RMT symbols</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @param[in] config Encoder configuration</span></span><br><span class="line"><span class="comment"> * @param[out] ret_encoder Returned encoder handle</span></span><br><span class="line"><span class="comment"> * @return</span></span><br><span class="line"><span class="comment"> *      - ESP_ERR_INVALID_ARG for any invalid arguments</span></span><br><span class="line"><span class="comment"> *      - ESP_ERR_NO_MEM out of memory when creating led strip encoder</span></span><br><span class="line"><span class="comment"> *      - ESP_OK if creating encoder successfully</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">esp_err_t</span> <span class="title function_">rmt_new_led_strip_encoder</span><span class="params">(<span class="type">const</span> <span class="type">led_strip_encoder_config_t</span> *config, <span class="type">rmt_encoder_handle_t</span> *ret_encoder)</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __cplusplus</span></span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li>led_strip_encoder.c</li>
</ul>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * SPDX-License-Identifier: Apache-2.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"esp_check.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"led_strip_encoder.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">char</span> *TAG = <span class="string">"led_encoder"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">    <span class="type">rmt_encoder_t</span> base;</span><br><span class="line">    <span class="type">rmt_encoder_t</span> *bytes_encoder;</span><br><span class="line">    <span class="type">rmt_encoder_t</span> *copy_encoder;</span><br><span class="line">    <span class="type">int</span> state;</span><br><span class="line">    <span class="type">rmt_symbol_word_t</span> reset_code;</span><br><span class="line">} <span class="type">rmt_led_strip_encoder_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">size_t</span> <span class="title function_">rmt_encode_led_strip</span><span class="params">(<span class="type">rmt_encoder_t</span> *encoder, <span class="type">rmt_channel_handle_t</span> channel, <span class="type">const</span> <span class="type">void</span> *primary_data, <span class="type">size_t</span> data_size, <span class="type">rmt_encode_state_t</span> *ret_state)</span></span><br><span class="line">{</span><br><span class="line">    <span class="type">rmt_led_strip_encoder_t</span> *led_encoder = __containerof(encoder, <span class="type">rmt_led_strip_encoder_t</span>, base);</span><br><span class="line">    <span class="type">rmt_encoder_handle_t</span> bytes_encoder = led_encoder-&gt;bytes_encoder;</span><br><span class="line">    <span class="type">rmt_encoder_handle_t</span> copy_encoder = led_encoder-&gt;copy_encoder;</span><br><span class="line">    <span class="type">rmt_encode_state_t</span> session_state = RMT_ENCODING_RESET;</span><br><span class="line">    <span class="type">rmt_encode_state_t</span> state = RMT_ENCODING_RESET;</span><br><span class="line">    <span class="type">size_t</span> encoded_symbols = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">switch</span> (led_encoder-&gt;state) {</span><br><span class="line">    <span class="keyword">case</span> <span class="number">0</span>: <span class="comment">// send RGB data</span></span><br><span class="line">        encoded_symbols += bytes_encoder-&gt;encode(bytes_encoder, channel, primary_data, data_size, &amp;session_state);</span><br><span class="line">        <span class="keyword">if</span> (session_state &amp; RMT_ENCODING_COMPLETE) {</span><br><span class="line">            led_encoder-&gt;state = <span class="number">1</span>; <span class="comment">// switch to next state when current encoding session finished</span></span><br><span class="line">        }</span><br><span class="line">        <span class="keyword">if</span> (session_state &amp; RMT_ENCODING_MEM_FULL) {</span><br><span class="line">            state |= RMT_ENCODING_MEM_FULL;</span><br><span class="line">            <span class="keyword">goto</span> out; <span class="comment">// yield if there's no free space for encoding artifacts</span></span><br><span class="line">        }</span><br><span class="line">    <span class="comment">// fall-through</span></span><br><span class="line">    <span class="keyword">case</span> <span class="number">1</span>: <span class="comment">// send reset code</span></span><br><span class="line">        encoded_symbols += copy_encoder-&gt;encode(copy_encoder, channel, &amp;led_encoder-&gt;reset_code,</span><br><span class="line">                                                <span class="keyword">sizeof</span>(led_encoder-&gt;reset_code), &amp;session_state);</span><br><span class="line">        <span class="keyword">if</span> (session_state &amp; RMT_ENCODING_COMPLETE) {</span><br><span class="line">            led_encoder-&gt;state = RMT_ENCODING_RESET; <span class="comment">// back to the initial encoding session</span></span><br><span class="line">            state |= RMT_ENCODING_COMPLETE;</span><br><span class="line">        }</span><br><span class="line">        <span class="keyword">if</span> (session_state &amp; RMT_ENCODING_MEM_FULL) {</span><br><span class="line">            state |= RMT_ENCODING_MEM_FULL;</span><br><span class="line">            <span class="keyword">goto</span> out; <span class="comment">// yield if there's no free space for encoding artifacts</span></span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">out:</span><br><span class="line">    *ret_state = state;</span><br><span class="line">    <span class="keyword">return</span> encoded_symbols;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">esp_err_t</span> <span class="title function_">rmt_del_led_strip_encoder</span><span class="params">(<span class="type">rmt_encoder_t</span> *encoder)</span></span><br><span class="line">{</span><br><span class="line">    <span class="type">rmt_led_strip_encoder_t</span> *led_encoder = __containerof(encoder, <span class="type">rmt_led_strip_encoder_t</span>, base);</span><br><span class="line">    rmt_del_encoder(led_encoder-&gt;bytes_encoder);</span><br><span class="line">    rmt_del_encoder(led_encoder-&gt;copy_encoder);</span><br><span class="line">    <span class="built_in">free</span>(led_encoder);</span><br><span class="line">    <span class="keyword">return</span> ESP_OK;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">esp_err_t</span> <span class="title function_">rmt_led_strip_encoder_reset</span><span class="params">(<span class="type">rmt_encoder_t</span> *encoder)</span></span><br><span class="line">{</span><br><span class="line">    <span class="type">rmt_led_strip_encoder_t</span> *led_encoder = __containerof(encoder, <span class="type">rmt_led_strip_encoder_t</span>, base);</span><br><span class="line">    rmt_encoder_reset(led_encoder-&gt;bytes_encoder);</span><br><span class="line">    rmt_encoder_reset(led_encoder-&gt;copy_encoder);</span><br><span class="line">    led_encoder-&gt;state = RMT_ENCODING_RESET;</span><br><span class="line">    <span class="keyword">return</span> ESP_OK;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">esp_err_t</span> <span class="title function_">rmt_new_led_strip_encoder</span><span class="params">(<span class="type">const</span> <span class="type">led_strip_encoder_config_t</span> *config, <span class="type">rmt_encoder_handle_t</span> *ret_encoder)</span></span><br><span class="line">{</span><br><span class="line">    <span class="type">esp_err_t</span> ret = ESP_OK;</span><br><span class="line">    <span class="type">rmt_led_strip_encoder_t</span> *led_encoder = <span class="literal">NULL</span>;</span><br><span class="line">    ESP_GOTO_ON_FALSE(config &amp;&amp; ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, <span class="string">"invalid argument"</span>);</span><br><span class="line">    led_encoder = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="keyword">sizeof</span>(<span class="type">rmt_led_strip_encoder_t</span>));</span><br><span class="line">    ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, <span class="string">"no mem for led strip encoder"</span>);</span><br><span class="line">    led_encoder-&gt;base.encode = rmt_encode_led_strip;</span><br><span class="line">    led_encoder-&gt;base.del = rmt_del_led_strip_encoder;</span><br><span class="line">    led_encoder-&gt;base.reset = rmt_led_strip_encoder_reset;</span><br><span class="line">    <span class="comment">// different led strip might have its own timing requirements, following parameter is for WS2812</span></span><br><span class="line">    <span class="type">rmt_bytes_encoder_config_t</span> bytes_encoder_config = {</span><br><span class="line">        .bit0 = {</span><br><span class="line">            .level0 = <span class="number">1</span>,</span><br><span class="line">            .duration0 = <span class="number">0.3</span> * config-&gt;resolution / <span class="number">1000000</span>, <span class="comment">// T0H=0.3us</span></span><br><span class="line">            .level1 = <span class="number">0</span>,</span><br><span class="line">            .duration1 = <span class="number">0.9</span> * config-&gt;resolution / <span class="number">1000000</span>, <span class="comment">// T0L=0.9us</span></span><br><span class="line">        },</span><br><span class="line">        .bit1 = {</span><br><span class="line">            .level0 = <span class="number">1</span>,</span><br><span class="line">            .duration0 = <span class="number">0.9</span> * config-&gt;resolution / <span class="number">1000000</span>, <span class="comment">// T1H=0.9us</span></span><br><span class="line">            .level1 = <span class="number">0</span>,</span><br><span class="line">            .duration1 = <span class="number">0.3</span> * config-&gt;resolution / <span class="number">1000000</span>, <span class="comment">// T1L=0.3us</span></span><br><span class="line">        },</span><br><span class="line">        .flags.msb_first = <span class="number">1</span> <span class="comment">// WS2812 transfer bit order: G7...G0R7...R0B7...B0</span></span><br><span class="line">    };</span><br><span class="line">    ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&amp;bytes_encoder_config, &amp;led_encoder-&gt;bytes_encoder), err, TAG, <span class="string">"create bytes encoder failed"</span>);</span><br><span class="line">    <span class="type">rmt_copy_encoder_config_t</span> copy_encoder_config = {};</span><br><span class="line">    ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&amp;copy_encoder_config, &amp;led_encoder-&gt;copy_encoder), err, TAG, <span class="string">"create copy encoder failed"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="type">uint32_t</span> reset_ticks = config-&gt;resolution / <span class="number">1000000</span> * <span class="number">50</span> / <span class="number">2</span>; <span class="comment">// reset code duration defaults to 50us</span></span><br><span class="line">    led_encoder-&gt;reset_code = (<span class="type">rmt_symbol_word_t</span>) {</span><br><span class="line">        .level0 = <span class="number">0</span>,</span><br><span class="line">        .duration0 = reset_ticks,</span><br><span class="line">        .level1 = <span class="number">0</span>,</span><br><span class="line">        .duration1 = reset_ticks,</span><br><span class="line">    };</span><br><span class="line">    *ret_encoder = &amp;led_encoder-&gt;base;</span><br><span class="line">    <span class="keyword">return</span> ESP_OK;</span><br><span class="line">err:</span><br><span class="line">    <span class="keyword">if</span> (led_encoder) {</span><br><span class="line">        <span class="keyword">if</span> (led_encoder-&gt;bytes_encoder) {</span><br><span class="line">            rmt_del_encoder(led_encoder-&gt;bytes_encoder);</span><br><span class="line">        }</span><br><span class="line">        <span class="keyword">if</span> (led_encoder-&gt;copy_encoder) {</span><br><span class="line">            rmt_del_encoder(led_encoder-&gt;copy_encoder);</span><br><span class="line">        }</span><br><span class="line">        <span class="built_in">free</span>(led_encoder);</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>使用方法:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">ESP_LOGI(TAG, <span class="string">"Install led strip encoder"</span>);</span><br><span class="line"><span class="type">rmt_encoder_handle_t</span> led_encoder = <span class="literal">NULL</span>;</span><br><span class="line"><span class="type">led_strip_encoder_config_t</span> encoder_config = {</span><br><span class="line">    .resolution = RMT_LED_STRIP_RESOLUTION_HZ,</span><br><span class="line">};</span><br><span class="line">ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&amp;encoder_config, &amp;led_encoder));</span><br></pre></td></tr></table></figure>

<h3 id="启用通道"><a href="#启用通道" class="headerlink" title="启用通道"></a>启用通道</h3><p>在正式发送数据前，使用<code>rmt_enable()</code>启动外设。启用 TX 通道会启用特定中断，并使硬件准备发送事务。</p>
<p>相反，<code>rmt_disable()</code> 会禁用中断并清除队列中的中断，同时禁用发射器和接收器。</p>
<h3 id="发送数据"><a href="#发送数据" class="headerlink" title="发送数据"></a>发送数据</h3><p><code>rmt_transmit()</code>函数用于启动发送事务：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_err_t</span> <span class="title function_">rmt_transmit</span><span class="params">(<span class="type">rmt_channel_handle_t</span> channel, <span class="type">rmt_encoder_t</span> *encoder, <span class="type">const</span> <span class="type">void</span> *payload, <span class="type">size_t</span> payload_bytes, <span class="type">const</span> <span class="type">rmt_transmit_config_t</span> *config)</span>;</span><br></pre></td></tr></table></figure>

<p><code>channel</code>:发送通道的句柄</p>
<p><code>encoder</code>:之前创建好的编码器</p>
<p><code>payload</code>:要发送的数据。</p>
<p><code>payload_bytes</code>:要发送的数据字节数。</p>
<p><code>config</code>:发送设置</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">    <span class="type">int</span> loop_count; <span class="comment">/*设置发送循环次数，设置-1为无限循环*/</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line">        <span class="type">uint32_t</span> eot_level : <span class="number">1</span>; <span class="comment">/*设置发送结束后电平 */</span></span><br><span class="line">    } flags;                    </span><br><span class="line">} <span class="type">rmt_transmit_config_t</span>;</span><br></pre></td></tr></table></figure>



<p>使用该函数后会创建一个事务，并将其发送到作业队伍中，并在中断中调度。因此这个是非阻塞的发送，可以使用<code>rmt_tx_wait_all_done()</code>等待发送结束。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));</span><br></pre></td></tr></table></figure>

<p>使用例子：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">rmt_transmit_config_t</span> tx_config = {</span><br><span class="line">        .loop_count = <span class="number">0</span>, <span class="comment">// no transfer loop</span></span><br><span class="line">    };</span><br><span class="line">ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, <span class="keyword">sizeof</span>(led_strip_pixels), &amp;tx_config));</span><br><span class="line">ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));</span><br></pre></td></tr></table></figure>

<h3 id="同步发送"><a href="#同步发送" class="headerlink" title="同步发送"></a>同步发送</h3><p>(待续)</p>
<h2 id="接收通道"><a href="#接收通道" class="headerlink" title="接收通道"></a>接收通道</h2><p>(待续)</p>
<h2 id="IRAM安全"><a href="#IRAM安全" class="headerlink" title="IRAM安全"></a>IRAM安全</h2><p>默认情况下，禁用 cache 时，写入/擦除主 flash 等原因将导致 RMT 中断延迟，事件回调函数也将延迟执行。在实时应用程序中，应避免此类情况。此外，当 RMT 事务依赖 <strong>交替</strong> 中断连续编码或复制 RMT 符号时，上述中断延迟将导致不可预测的结果。</p>
<p>因此，可以启用 Kconfig 选项 <a target="_blank" rel="noopener" href="https://docs.espressif.com/projects/esp-idf/zh_CN/v5.0.6/esp32c3/api-reference/kconfig.html#config-rmt-isr-iram-safe">CONFIG_RMT_ISR_IRAM_SAFE</a>，该选项：</p>
<ol>
<li>支持在禁用 cache 时启用所需中断</li>
<li>支持将 ISR 使用的所有函数存放在 IRAM 中 </li>
<li>支持将驱动程序实例存放在 DRAM 中，以防其意外映射到 PSRAM 中</li>
</ol>
<p>启用该选项可以保证 cache 禁用时的中断运行，但会相应增加 IRAM 占用。</p>
<p>另外一个 Kconfig 选项 <a target="_blank" rel="noopener" href="https://docs.espressif.com/projects/esp-idf/zh_CN/v5.0.6/esp32c3/api-reference/kconfig.html#config-rmt-recv-func-in-iram">CONFIG_RMT_RECV_FUNC_IN_IRAM</a> 可以将 <a target="_blank" rel="noopener" href="https://docs.espressif.com/projects/esp-idf/zh_CN/v5.0.6/esp32c3/api-reference/peripherals/rmt.html#_CPPv411rmt_receive20rmt_channel_handle_tPv6size_tPK20rmt_receive_config_t"><code>rmt_receive()</code></a> 函数放进内部的 IRAM 中，从而当 flash cache 被关闭的时候，这个函数也能够被使用。</p>
<h2 id="线程安全"><a href="#线程安全" class="headerlink" title="线程安全"></a>线程安全</h2><p><code>rmt_new_tx_channel()</code>、<code>rmt_new_rx_channel()</code> 和 <code>rmt_new_sync_manager() </code>线程安全，其他以 <code>rmt_channel_handle_t</code> 和 <code>rmt_sync_manager_handle_t</code> 作为第一个位置参数的函数均非线程安全，调用时应注意互斥锁保护。</p>
<p><code>rmt_receive()</code>可以在中断中使用。</p>

        </div>
        
<blockquote class="copyright">
    <p><strong>本文链接 : </strong><a class="permalink" href="https://lostacnet.top/post/32304/">https://lostacnet.top/post/32304/</a></p>
    <p><strong>This article is available under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="noopener noreferrer">Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)</a> License  转载请注明出处</strong></p>
</blockquote>


    </article>
    
    <section id="comments">
        
    </section>


    

</main>


<aside style="" id="sidebar" class="aside aside-fixture">
    <div class="toc-sidebar">
        <nav id="toc" class="article-toc">
            <h3 class="toc-title">文章目录</h3>
            <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#ESP-IDF%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-RMT%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="toc-number">1.</span> <span class="toc-text">ESP-IDF学习笔记-RMT的使用</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%A4%96%E8%AE%BE%E7%AE%80%E4%BB%8B"><span class="toc-number">1.1.</span> <span class="toc-text">外设简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%91%E9%80%81%E9%80%9A%E9%81%93"><span class="toc-number">1.2.</span> <span class="toc-text">发送通道</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%89%E8%A3%85TX%E9%80%9A%E9%81%93"><span class="toc-number">1.2.1.</span> <span class="toc-text">安装TX通道</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BD%BD%E6%B3%A2%E8%B0%83%E5%88%B6"><span class="toc-number">1.2.2.</span> <span class="toc-text">载波调制</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#RMT%E7%BC%96%E7%A0%81%E5%99%A8"><span class="toc-number">1.2.3.</span> <span class="toc-text">RMT编码器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%90%AF%E7%94%A8%E9%80%9A%E9%81%93"><span class="toc-number">1.2.4.</span> <span class="toc-text">启用通道</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%91%E9%80%81%E6%95%B0%E6%8D%AE"><span class="toc-number">1.2.5.</span> <span class="toc-text">发送数据</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%90%8C%E6%AD%A5%E5%8F%91%E9%80%81"><span class="toc-number">1.2.6.</span> <span class="toc-text">同步发送</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8E%A5%E6%94%B6%E9%80%9A%E9%81%93"><span class="toc-number">1.3.</span> <span class="toc-text">接收通道</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#IRAM%E5%AE%89%E5%85%A8"><span class="toc-number">1.4.</span> <span class="toc-text">IRAM安全</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8"><span class="toc-number">1.5.</span> <span class="toc-text">线程安全</span></a></li></ol></li></ol>
        </nav>
    </div>
</aside>





        </section>
        <footer class="hidden lg:block fixed bottom-0 left-0 sm:w-1/12 lg:w-1/6 bg-gray-100 z-40">
    
    <div class="footer-social-links">
        
            <a target="_blank" rel="noopener" href="https://github.com/LOStacNet">
                <i class="iconfont icon-github"></i>
            </a>
        
            <a target="_blank" rel="noopener" href="https://gitee.com/LOStacNet">
                <i class="iconfont icon-project"></i>
            </a>
        
    </div>
    
    
</footer>

        <div id="mask" class="hidden mask fixed inset-0 bg-gray-900 opacity-75 z-40"></div>
        <div id="search-view-container" class="hidden shadow-xl"></div>
        
<script src="/js/dom-event.min.js"></script>



<script src="/js/local-search.min.js"></script>



    <script src="//cdn.jsdelivr.net/npm/lightgallery.js@1.1.3/dist/js/lightgallery.min.js"></script>
    
<script src="/js/light-gallery.min.js"></script>






    </body>
</html>
